package gui.utils;

import gui.GuiManager;
import gui.actions.DoubleActionListener;
import gui.components.UIFSplitPane;
import gui.interfaces.ValidatorInterface;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.URL;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public final class ComponentUtils {

    public static void setAntiAliased(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    }
    
	public static String addLineBreaks(String text, int maxLineLength) {
		return addLineBreaks(text, maxLineLength, "\n");
	}
	
	public static String addLineBreaks(String text, int maxLineLength, String lineBreak) {
		int index = text.indexOf(lineBreak, 0);
		if (index != -1) {
			String str1 = addLineBreaks(text.substring(0, index), maxLineLength, lineBreak);
			String str2 = addLineBreaks(text.substring(index+lineBreak.length()), maxLineLength, lineBreak);
			return str1 + lineBreak + str2;
		} else {	
			ArrayList<String> lines = new ArrayList<String>();
			String suffix = text;
			while (suffix.length() > maxLineLength) {
				String prefix = suffix.substring(0, maxLineLength);
				suffix =  suffix.substring(maxLineLength);
				int endIndex = prefix.lastIndexOf(' ');
				lines.add(prefix.substring(0, endIndex) + lineBreak);
				suffix = prefix.substring(endIndex+1) + suffix;	
			}
			lines.add(suffix);
			String result = "";
			for (String line : lines) {
				result += line;
			}
			return result;	
		}
	}
	
    public static JButton createButton(String text) {
        JButton button = new JButton(text);
        button.setFocusPainted(true);
        button.setBorderPainted(true);
        button.setContentAreaFilled(true);
        return button;
    }
    
    public static JButton createButton(String text, String icon) {
        return createButton(text, icon, false);
    }

    public static JButton createButton(String text, String icon, boolean flat) {
        ImageIcon iconNormal = readImageIcon(icon + ".png");
        ImageIcon iconHighlight = readImageIcon(icon + "_highlight.png");
        ImageIcon iconPressed = readImageIcon(icon + "_pressed.png");

        JButton button = new JButton(text, iconNormal);
        button.setFocusPainted(!flat);
        button.setBorderPainted(!flat);
        button.setContentAreaFilled(!flat);
        if (iconHighlight != null) {
            button.setRolloverEnabled(true);
           button.setRolloverIcon(iconHighlight);
        }
        if (iconPressed != null)
          button.setPressedIcon(iconPressed);
        return button;
    }

    public static JButton createIconButton(String icon) {
        JButton button = new JButton(readImageIcon(icon));
        button.setFocusPainted(true);
        button.setBorderPainted(true);
        button.setContentAreaFilled(true);
        return button;
    }

    public static void centerOnScreen(Component component) {
        Dimension paneSize = component.getSize();
        Dimension screenSize = component.getToolkit().getScreenSize();
        component.setLocation(
            (screenSize.width - paneSize.width) / 2,
            (screenSize.height - paneSize.height) / 2);
    }

    public static ImageIcon readImageIcon(String fileName) {
        URL url = Thread.currentThread().getContextClassLoader().getResource("gui/images/" + fileName);
        if (url == null) {
            return null;
        }

        return new ImageIcon(java.awt.Toolkit.getDefaultToolkit().getImage(url));
    }
    
    public static ImageIcon readScaledImageIcon(String fileName, int width, int height) {
        Image image = readImage(fileName);
        if (image == null) {
            return null;
        }
        Image scaledImage = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        return new ImageIcon(scaledImage);
    }
    
    public static Image readImage(String fileName) {
        URL url = Thread.currentThread().getContextClassLoader().getResource("gui/images/" + fileName);
        if (url == null)
            return null;
        return java.awt.Toolkit.getDefaultToolkit().getImage(url);
    }
    
	public static JLabel createLabel(String text, String image) {
        ImageIcon icon = readImageIcon(image + ".png");
        JLabel label = new JLabel(text, icon, JLabel.LEFT);
        return label;
	}
	
    /**
     * Creates and answers a <code>JScrollPane</code> that has an empty
     * border.
     */
    public static JScrollPane createStrippedScrollPane(Component component) {
        JScrollPane scrollPane = new JScrollPane(component);
        scrollPane.setBorder(BorderFactory.createEmptyBorder());
        return scrollPane;
    }

    /**
     * Creates and returns a <code>JSplitPane</code> that has empty borders.
     * Useful to avoid duplicate decorations, for example if the split pane
     * is contained by other components that already provide a border.
     * 
     * @param orientation    the split pane's orientation: horizontal or vertical
     * @param comp1          the top/left component
     * @param comp2          the bottom/right component
     * @param resizeWeight   indicates how to distribute extra space
     * @return a split panes that has an empty border
     */
    public static JSplitPane createStrippedSplitPane(int orientation, Component comp1, Component comp2, double resizeWeight) {
        JSplitPane split = UIFSplitPane.createStrippedSplitPane(orientation, comp1, comp2);
        split.setResizeWeight(resizeWeight);
        return split;
    }
    
    public static void installWindowClosingListener(final JFrame frame) {
    	frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    	frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent evt)
			{
		        showQuitDialog(frame);
			}
		});
    }
    
	public static void showQuitDialog(final JFrame frame) {
		int confirm = JOptionPane.showConfirmDialog(frame, "Are you sure you want to quit Fictionator?",
                "Quit application", JOptionPane.YES_NO_OPTION);

        if (confirm == JOptionPane.YES_OPTION)
        {
        	GuiManager.quitApplication();
        }
	}
	
	public static ActionListener createDoubleAction(ActionListener first, ActionListener second) {
		return new DoubleActionListener(first, second);
	}
	
	public static void installValidator(final JTextField textField, final ValidatorInterface validator) {
		textField.getDocument().addDocumentListener(new DocumentListener() {			
			@Override
			public void removeUpdate(DocumentEvent e) {
				validator.validate(textField.getText());
			}
			
			@Override
			public void insertUpdate(DocumentEvent e) {
				validator.validate(textField.getText());	
			}
			
			@Override
			public void changedUpdate(DocumentEvent e) {
				validator.validate(textField.getText());				
			}
		});	
	}
	
	public static void installValidator(final JSpinner spinner, final ValidatorInterface validator) {
		JComponent editor = spinner.getEditor();
	    if (editor instanceof JSpinner.DefaultEditor) {
	        JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
	        installValidator(textField,validator);
	    }
	}
    
}
